#include "renderer.h"

RRClipping::RRClipping()
{
  Xmax = 1.0f; Xmin = -1.0f;
  Ymax = 1.0f; Ymin = -1.0f;
}

uint8_t RRClipping::rrOutCode(float x, float y)
{
  uint8_t o;
  o = 0b0000;
  if(y > Ymax) o |= 0b1000;
  else if(y < Ymin) o |= 0b0100;
  if(x > Xmax) o |= 0b0010;
  else if(x < Xmin) o |= 0b0001;

  return o;
}

void RRClipping::rrClipping(RRPrim *src, RRPrim *dest)
{
  RRVertex s, t;
  int cnt;
  dest->rrSetType(RR_POLYGON);
  prim = dest;
  cnt = src->rrGetVertsNum();
  for(int i=0; i<cnt-1; i++) {
    s = src->rrGetVert(i);
    t = src->rrGetVert(i+1);
    rrCohenSutherland(s, t, s.x, s.y, t.x, t.y);
  }
  // s = src->rrGetVert(cnt-1);
  // t = src->rrGetVert(0);
  // rrCohenSutherland(s, t, s.x, s.y, t.x, t.y);
}

void RRClipping::rrCohenSutherland(RRVertex s, RRVertex t, float Xp, float Yp, float Xq, float Yq)
{
  uint8_t o1, o2;
  o1 = rrOutCode(Xp, Yp);
  o2 = rrOutCode(Xq, Yq);
  //printf("%d %d\n", o1, o2);

  float X, Y;
  float t1, t2;
  RRVertex V;
  if(o1 == 0 && o2 == 0) {
    // primitiveに追加
    if(Xp == Xq && Yp == Yq) {	// 一点のみ
      // 内挿
      t1 = ((Xp - s.x) * (t.x - s.x) + (Yp - s.y) * (t.y - s.y)) / ((t.x - s.x) * (t.x - s.x) + (t.y - s.y) * (t.y - s.y));
      V.x = Xp; V.y = Yp; V.z = (1 - t1) * s.z + t1 * t.z;
      V.w = (1 - t1) * s.w + t1 * t.w;
      for(int i = 0; i<4; i++)
	V.c[i] = (1 - t1) * s.c[i] + t1 * t.c[i];
      prim->rrSetVert(V);
    }
    else {
      // それぞれの点の要素に内挿した値を入れる
      t1 = ((Xp - s.x) * (t.x - s.x) + (Yp - s.y) * (t.y - s.y)) / ((t.x - s.x) * (t.x - s.x) + (t.y - s.y) * (t.y - s.y));
      t2 = ((Xq - s.x) * (t.x - s.x) + (Yq - s.y) * (t.y - s.y)) / ((t.x - s.x) * (t.x - s.x) + (t.y - s.y) * (t.y - s.y));
      V.x = Xp; V.y = Yp; V.z = (1 - t1) * s.z + t1 * t.z;
      V.w = (1 - t1) * s.w + t1 * t.w;
      for(int i = 0; i<4; i++)
	V.c[i] = (1 - t1) * s.c[i] + t1 * t.c[i];
      prim->rrSetVert(V);
      V.x = Xq; V.y = Yq; V.z = (1 - t2) * s.z + t2 * t.z;
      V.w = (1 - t2) * s.w + t2 * t.w;
      for(int i = 0; i<4; i++)
	V.c[i] = (1 - t2) * s.c[i] + t2 * t.c[i];
      prim->rrSetVert(V);
    }
  }
  else if((o1 & o2) != 0) {
    // 範囲外
  }
  else {
    // o1のクリッピング
    if((o1 & 0b1000) != 0) {	// o1上切り取り
      if(Yp != Yq)
	X = Xq + (Xp - Xq) * (Ymax - Yq) / (Yp - Yq);
      else
	X = Xq;
      Y = Ymax;
      rrCohenSutherland(s, t, X, Y, Xq, Yq);
    }
    else if((o1 & 0b0100) != 0) {	// o1下切り取り
      if(Yp != Yq)
	X = Xq + (Xp - Xq) * (Ymin - Yq) / (Yp - Yq);
      else
	X = Xq;
      Y = Ymin;
      rrCohenSutherland(s, t, X, Y, Xq, Yq);
    }
    else if((o1 & 0b0010) != 0) {	// o1右切り取り
      if(Xp != Xq)
	Y = Yq + (Yp - Yq) * (Xmax - Xq) / (Xp - Xq);
      else
	Y = Yq;
      X = Xmax;
      printf("hell0 %f %f\n", X, Y);
      rrCohenSutherland(s, t, X, Y, Xq, Yq);
    }
    else if((o1 & 0b0001) != 0) {	// o1左切り取り
      if(Xp != Xq)
	Y = Yq + (Yp - Yq) * (Xmin - Xq) / (Xp - Xq);
      else
	Y = Yq;
      X = Xmin;
      rrCohenSutherland(s, t, X, Y, Xq, Yq);
    }
    // o2のクリッピング
    else if((o2 & 0b1000) != 0) {	// o2上切り取り
      if(Yq != Yp)
	X = Xp + (Xq - Xp) * (Ymax - Yp) / (Yq - Yp);
      else
	X = Xp;
      Y = Ymax;
      rrCohenSutherland(s, t, Xp, Yp, X, Y);
    }
    else if((o2 & 0b0100) != 0) {	// o2下切り取り
      if(Yq != Yp)
	X = Xp + (Xq - Xp) * (Ymin - Yp) / (Yq - Yp);
      else
	X = Xp;
      Y = Ymin;
      rrCohenSutherland(s, t, Xp, Yp, X, Y);
    }
    else if((o2 & 0b0010) != 0) {	// o2右切り取り
      if(Xq != Xp)
	Y = Yp + (Yq - Yp) * (Xmax - Xp) / (Xq - Xp);
      else
	Y = Yp;
      X = Xmax;
      rrCohenSutherland(s, t, Xp, Yp, X, Y);
    }
    else if((o2 & 0b0001) != 0) {	// o2左切り取り
      if(Xq != Xp)
	Y = Yp + (Yq - Yp) * (Xmin - Xp) / (Xq - Xp);
      else
	Y = Yp;
      X = Xmin;
      rrCohenSutherland(s, t, Xp, Yp, X, Y);
    }    
  }
}
